//
//  FileParse.cpp
//  ConstructGccfg2.0
//
//  Created by Bryce Holton on 12/8/12.
//  Copyright (c) 2012 Bryce Holton. All rights reserved.
//

#include "FileParse.h"

FileParse::FileParse(string fileName)
{    
    inputFile.open(FILEPATH + fileName);
}
FileParse::~FileParse()
{
    inputFile.close();
}
ProgramFunction *FileParse::ParseFunction()
{
    ProgramFunction *newFunction = new ProgramFunction();
    ControlFlowGraph *newCfg = new ControlFlowGraph();
    string inputLine;
    vector<string> inputLineTokens;
    
    GetStringFromFile(inputLine);
    while (inputLine.find("Function") == string::npos && inputLine != "EOF")
    {
        // Skip past blank space.
        GetStringFromFile(inputLine);
    }
    if (inputLine != "EOF")
    {
        /****** First get the functions name ******/
        SplitString(inputLine, inputLineTokens, " \t");        
        newCfg->SetFunctionName(inputLineTokens[2]);
        inputLineTokens.clear();
        
        // Next build all the basic blocks for the function.
        BuildBasicBlocks(inputLine, *newCfg);
        newFunction->SetCfg(*newCfg);
        
        while (inputLine.find("Loop") == string::npos && inputLine.find("succs") == string::npos)
        {
            // Move to the Loop ID, or to BB connections.
            GetStringFromFile(inputLine);
        }
        if (inputLine.find("Loop") != string::npos)
        {
            // We found loops in this function, build them.
            BuildFunctionLoops(inputLine, *newFunction);
        }

        // Next connect all the basic blocks for the function.
        ConnectBasicBlocks(inputLine, *newCfg);
        
        while (inputLine.find( newCfg->GetFunctionName() ) == string::npos)
        {
            // Move past any ssa info.
            GetStringFromFile(inputLine);
        }
        GetStringFromFile(inputLine); // Move one line so we reach "{"

        // Now we insert all the code into the bb and find the size of the function.
        newFunction->SetSize( InsertCodeIntoBasicBlocks(inputLine, *newCfg) );
        
        // Function components are built, now we need to clean up.
        newCfg->SetRootBlock( *RemoveReferencesToUneededBlocks(*newCfg) );
    }
    else
    {
        newFunction = NULL;
    }
    return newFunction;
}
BasicBlock *FileParse::RemoveReferencesToUneededBlocks(ControlFlowGraph &cfg)
{
    vector<BasicBlock *> blockList = cfg.GetBlockList();
    BasicBlock *rootBlock = NULL;
    
    for (unsigned int i = 0; i < blockList.size(); i++)
    {
        if (blockList[i]->GetDecendantEdges().size() > 0 && blockList[i]->GetAncestorEdges().size() == 0)
        {
            rootBlock = blockList[i];
        }
        if (blockList[i]->GetDecendantEdges().size() == 0 && blockList[i]->GetAncestorEdges().size() == 0 && blockList[i]->GetCode().size() == 0)
        {
            cfg.RemoveBlockFromList(*blockList[i]);
        }
    }
    if (blockList.size() == 1)
    {
        rootBlock = blockList[0];
    }
    
    return rootBlock;
}
int FileParse::InsertCodeIntoBasicBlocks(string &inLine, ControlFlowGraph &cfg)
{
    int functionSize = 0;
    vector<string> tokens;
    bool foundBlockCode = false;
    BasicBlock *foundBlock = NULL;
    
    while (inLine != "}")
    {
        if (foundBlockCode)
        {
            if (inLine.size() == 0)
            {
                foundBlockCode = false;
            }
            else
            {
                foundBlock->SetLineOfCode(inLine);
            }
        }
        if (inLine.find("<bb") != string::npos && inLine.find(">:") != string::npos)
        {
            foundBlockCode = true;
            SplitString(inLine, tokens, " \t<>");
            foundBlock = cfg.FindBlockInList( atoi( tokens[1].c_str() ) );
            tokens.clear();
        }
        
        functionSize++;
        GetStringFromFile(inLine);
    }
    functionSize++;
    
    return functionSize;
}
void FileParse::ConnectBasicBlocks(string &inLine, ControlFlowGraph &cfg)
{
    vector<string> tokens;
    
    while (inLine.find("succs") != string::npos)
    {
        BasicBlock *parent;
        vector<int> children;
        unsigned int i;
        
        // Build the graph until we get to the bb code.
        SplitString(inLine, tokens, " \tsuccs{}");
        parent = cfg.FindBlockInList( atoi( tokens[1].c_str() ) );
        for (i = 2; i < tokens.size(); i++)
        {
            children.push_back( atoi( tokens[i].c_str() ) );
        }
        tokens.clear();
        
        for (i = 0; i < children.size(); i++)
        {
            BasicBlock *child = cfg.FindBlockInList(children[i]);
            
            parent->SetDecendantEdge(*child);
        }
        children.clear();
        GetStringFromFile(inLine);
    }
}
void FileParse::BuildFunctionLoops(string &inLine, ProgramFunction &function)
{
    ControlFlowGraph *cfg = function.GetCfg();
    vector<string> tokens;
    
    while (inLine.find("succs") == string::npos)
    {
        if (inLine != ";;")
        {
            SplitString(inLine, tokens, " \t");
            ControlFlowGraphLoop *loop = new ControlFlowGraphLoop( atoi( tokens[2].c_str() ) );
            loop->SetFunctionName(cfg->GetFunctionName());
            tokens.clear();
            
            GetStringFromFile(inLine);
            SplitString(inLine, tokens, " \t,");
            loop->SetRootBlock( *cfg->FindBlockInList( atoi( tokens[2].c_str() ) ) );
            loop->SetExitBlock( *cfg->FindBlockInList( atoi( tokens[4].c_str() ) ) );
            tokens.clear();
            
            GetStringFromFile(inLine);
            GetStringFromFile(inLine);
            SplitString(inLine, tokens, " \t");
            
            vector<BasicBlock *> loopBlocks;
            for (unsigned int i = 2; i < tokens.size(); i++)
            {
                loopBlocks.push_back( cfg->FindBlockInList( atoi( tokens[i].c_str() ) ) );
            }
            loop->SetBlockList(loopBlocks);
            loopBlocks.clear();
            tokens.clear();
            function.SetLoop(*loop);
        }
        GetStringFromFile(inLine);
    }
}
void FileParse::BuildBasicBlocks(string &inLine, ControlFlowGraph &cfg)
{
    vector<string> tokens;
    vector<BasicBlock *> blockList;
    int rootId, exitId;
    
    while (inLine.find("Loop 0") == string::npos)
    {
        // Get to the nodes of the cfg.
        GetStringFromFile(inLine);
    }
    GetStringFromFile(inLine);
    SplitString(inLine, tokens, " \t,");
    rootId = atoi( tokens[2].c_str() );
    exitId = atoi( tokens[4].c_str() );
    while (inLine.find("nodes:") == string::npos)
    {
        // We found the nodes of the cfg.
        GetStringFromFile(inLine);
    }
    SplitString(inLine, tokens, " \t");
    for (unsigned int i = 2; i < tokens.size(); i++)
    {
        // Create each node of the CFG.
        BasicBlock *block = new BasicBlock( atoi( tokens[i].c_str() ) );
        
        blockList.push_back(block);
    }
    cfg.SetBlockList(blockList);
    cfg.SetRootBlock( *cfg.FindBlockInList(rootId) );
    cfg.SetExitBlock( *cfg.FindBlockInList(exitId) );
}
void FileParse::GetStringFromFile(string &str)
{
    if ( inputFile.is_open() && inputFile.good() )
    {
        getline (inputFile, str);
    }
    else
    {
        str = "EOF";
    }
}
